/*
 * cng.c
 *
 *  Created on: Sep 20, 2013
 *      Author: Ken Arok
 */


#include "config_apps.h"

#if APPLICATION_CNG

#include <string.h>
#include "mydefs.h"
#include "timers_hw.h"
#include "gpio.h"
#include "inter_chip.h"
#include "cng.h"


/* For debuging purpose. */
#define CGN_DEBUG_SERIAL		0


#if CGN_DEBUG_SERIAL
#include "io.h"

#define debug_cng(a, b, c, d)	vIO_Write(a, b, c, d);

#else

#define debug_cng(a, b, c, d)

#endif

/* CNG Application Command. */

//! Command with argument
#define CNG_TURN_DISPLAY_ALARM_ON		0x81
#define CNG_TURN_DISPLAY_ALARM_OFF		0x82
#define CNG_TURN_DISPLAY_ALARM_BLINK	0x83


/* Function of turn off Buzzer. */
static TimerFuncVoid_t _funcTurnDisplayAlarmOff[2];
/* Function of turn on Buzzer. */
static TimerFuncVoid_t _funcTurnDisplayAlarmOn[2];
/* Timer for Display Alarm ON. */
static volatile uint32_t *_tmrDisplayAlarmON[2] = {NULL, NULL};
/* Timer for Display Alarm OFF. */
static volatile uint32_t *_tmrDisplayAlarmOFF[2] = {NULL, NULL};

static uint8_t prvDisplayAlarmSwitch(const uint8_t _idx, const uint8_t _on_off, uint32_t _val);
static void prvTurnOnDisplayAlarm1(void *_tmr);
static void prvTurnOnDisplayAlarm2(void *_tmr);
static void prvTurnOffDisplayAlarm1(void *_tmr);
static void prvTurnOffDisplayAlarm2(void *_tmr);

static uint8_t _DisplayAlarmON_Active_Flag[2] = {0, 0};
static uint8_t _DisplayAlarmOFF_Active_Flag[2] = {0, 0};

/* -------------------------------------------------------------------------------------- */

void vStartCGN_Apps(void)
{
	inter_chip_t _ic_opt;
	uint8_t i, _res, _DisplayAlarmIdx;
	uint8_t *_ptr;
	char *_end = NULL;
	uint32_t _Arg;

	/* Obtain Timer for Display Alarm ON. */
	for (i = 0; i < 2; i++) {
		_tmrDisplayAlarmON[i] = vTimer500msTake();
		if(_tmrDisplayAlarmON[i] == NULL) {
			while(1);
		}
	}

	/* Obtain Timer for Display Alarm. */
	for (i = 0; i < 2; i++) {
		_tmrDisplayAlarmOFF[i] = vTimer500msTake();
		if(_tmrDisplayAlarmOFF[i] == NULL) {
			while(1);
		}
	}


#if CGN_DEBUG_SERIAL
	vIO_Open(IOP_COM1, 0);
	vIO_Ctrl(IOP_COM1, IORC_SET_DEFAULT, NULL);
	vIO_Ctrl(IOP_COM1, IORC_SET_TRANSFER_POLLED_TX, NULL);
	//vIO_Ctrl(IOP_COM1, IORC_SAVE_SETTING_TO_ROM, NULL);

	debug_cng(IOP_COM1, (const void *)("start listening\n\r"), 17, IORWF_BYTE_ORDER);
#endif

	for(;;)
	{
		_res = vADO_Listen(&_ic_opt);
		if(_res == 2) {
			_ptr = _ic_opt.pBuf;
			i = _ptr[2];
			_ptr[2] = '\0';
			_DisplayAlarmIdx = (uint8_t)strtoul((const char *)_ptr, &_end, 10);
			_DisplayAlarmIdx--;
			_ptr[2] = i;

			i = _ptr[12];
			_ptr[12] = '\0';
			_Arg = (uint32_t)strtoul((const char *)&_ptr[2], &_end, 10);
			_ptr[12] = i;

			debug_cng(IOP_COM1, (const void *)_ic_opt.pBuf, 12, IORWF_BYTE_ORDER);

			switch(_ic_opt.cmd) {
				case CNG_TURN_DISPLAY_ALARM_ON:
					prvDisplayAlarmSwitch(_DisplayAlarmIdx, iON, _Arg * 2);
				break;

				case CNG_TURN_DISPLAY_ALARM_OFF:
					prvDisplayAlarmSwitch(_DisplayAlarmIdx, iOFF, _Arg * 2);
				break;

				case CNG_TURN_DISPLAY_ALARM_BLINK:
				break;

				default: break;
			}
		}
	#if CGN_DEBUG_SERIAL
		else if(_res == 1) {
			debug_cng(IOP_COM1, (const void *)&_ic_opt.cmd, 1, IORWF_BYTE_ORDER);
		}
	#endif
	}
}


/* --------------------------------------------------------------------------------- */

static uint8_t prvDisplayAlarmSwitch(const uint8_t _idx, const uint8_t _on_off, uint32_t _val)
{
	if((_idx >= 2) && (_idx != 0xFF)) return 1;

	switch(_on_off)
	{
		case iON:
			/* Turn ON infinite. */
			if(_val == 0) _val = 0xFFFFFFFF;

			/* All Display Alarm ON. */
			if(_idx == 0xFF) {
				/* Turn Display Alarm ON via Timer. */
				if(_tmrDisplayAlarmON[0] == NULL) {
					/* Obtain Timer. */
					_tmrDisplayAlarmON[0] = vTimer500msTake();
				}

				if(_tmrDisplayAlarmON[1] == NULL) {
					/* Obtain Timer. */
					_tmrDisplayAlarmON[1] = vTimer500msTake();
				}

				if(_tmrDisplayAlarmON[0] != NULL) {
					if(_DisplayAlarmON_Active_Flag[0] < 2) {
						*_tmrDisplayAlarmON[0] = 0;
					}

					if(_DisplayAlarmOFF_Active_Flag[0] < 2) {
						/* Set timeout. */
						*_tmrDisplayAlarmOFF[0] = _val;
					}

					if(_DisplayAlarmON_Active_Flag[0] == 0) {
						_DisplayAlarmON_Active_Flag[0] = 1;
						_funcTurnDisplayAlarmOn[0] = &prvTurnOnDisplayAlarm1;
						vTimer500msFuncReg(_funcTurnDisplayAlarmOn[0], (void *)_tmrDisplayAlarmON[0]);
					}

					/* Register function to turn off. */
					if(_DisplayAlarmOFF_Active_Flag[0] == 0) {
						_DisplayAlarmOFF_Active_Flag[0] = 1;
						_funcTurnDisplayAlarmOff[0] = &prvTurnOffDisplayAlarm1;
						vTimer500msFuncReg(_funcTurnDisplayAlarmOff[0], (void *)_tmrDisplayAlarmOFF[0]);
					}
				}

				if(_tmrDisplayAlarmON[1] != NULL) {
					if(_DisplayAlarmON_Active_Flag[1] < 2) {
						*_tmrDisplayAlarmON[1] = 0;
					}

					if(_DisplayAlarmOFF_Active_Flag[1] < 2) {
						/* Set timeout. */
						*_tmrDisplayAlarmOFF[1] = _val;
					}

					if(_DisplayAlarmON_Active_Flag[1] == 0) {
						_DisplayAlarmON_Active_Flag[1] = 1;
						_funcTurnDisplayAlarmOn[1] = &prvTurnOnDisplayAlarm2;
						vTimer500msFuncReg(_funcTurnDisplayAlarmOn[1], (void *)_tmrDisplayAlarmON[1]);
					}

					/* Register function to turn off. */
					if(_DisplayAlarmOFF_Active_Flag[1] == 0) {
						_DisplayAlarmOFF_Active_Flag[1] = 1;
						_funcTurnDisplayAlarmOff[1] = &prvTurnOffDisplayAlarm2;
						vTimer500msFuncReg(_funcTurnDisplayAlarmOff[1], (void *)_tmrDisplayAlarmOFF[1]);
					}
				}
			}
			/* One selected Display Alarm ON. */
			else {
				/* Turn Display Alarm ON via Timer. */
				if(_tmrDisplayAlarmON[_idx] == NULL) {
					/* Obtain Timer. */
					_tmrDisplayAlarmON[_idx] = vTimer500msTake();
				}

				/* Turn Display Alarm OFF (timeout) via Timer. */
				if(_tmrDisplayAlarmOFF[_idx] == NULL) {
					/* Obtain Timer. */
					_tmrDisplayAlarmOFF[_idx] = vTimer500msTake();
				}

				if((_tmrDisplayAlarmON[_idx] != NULL) && (_tmrDisplayAlarmOFF[_idx] != NULL)) {
					if(_DisplayAlarmON_Active_Flag[_idx] < 2) {
						/* Turn on immediately. */
						*_tmrDisplayAlarmON[_idx] = 0;
					}

					if(_DisplayAlarmOFF_Active_Flag[_idx] < 2) {
						/* Set timeout. */
						*_tmrDisplayAlarmOFF[_idx] = _val;
					}

					if(_idx == 0) {
						/* Register function to turn on. */
						if(_DisplayAlarmON_Active_Flag[0] == 0) {
							_DisplayAlarmON_Active_Flag[0] = 1;
							_funcTurnDisplayAlarmOn[0] = &prvTurnOnDisplayAlarm1;
							vTimer500msFuncReg(_funcTurnDisplayAlarmOn[0], (void *)_tmrDisplayAlarmON[0]);
						}

						/* Register function to turn off. */
						if(_DisplayAlarmOFF_Active_Flag[0] == 0) {
							_DisplayAlarmOFF_Active_Flag[0] = 1;
							_funcTurnDisplayAlarmOff[0] = &prvTurnOffDisplayAlarm1;
							vTimer500msFuncReg(_funcTurnDisplayAlarmOff[0], (void *)_tmrDisplayAlarmOFF[0]);
						}
					}
					else if(_idx == 1) {
						if(_DisplayAlarmON_Active_Flag[1] == 0) {
							_DisplayAlarmON_Active_Flag[1] = 1;
							_funcTurnDisplayAlarmOn[1] = &prvTurnOnDisplayAlarm2;
							vTimer500msFuncReg(_funcTurnDisplayAlarmOn[1], (void *)_tmrDisplayAlarmON[1]);
						}

						/* Register function to turn off. */
						if(_DisplayAlarmOFF_Active_Flag[1] == 0) {
							_DisplayAlarmOFF_Active_Flag[1] = 1;
							_funcTurnDisplayAlarmOff[1] = &prvTurnOffDisplayAlarm2;
							vTimer500msFuncReg(_funcTurnDisplayAlarmOff[1], (void *)_tmrDisplayAlarmOFF[1]);
						}
					}
				}
			}
		break;

		case iOFF:
			/* All Display Alarm OFF. */
			if(_idx == 0xFF) {
				/* Turn Display Alarm OFF via Timer. */
				if(_tmrDisplayAlarmOFF[0] == NULL) {
					/* Obtain Timer. */
					_tmrDisplayAlarmOFF[0] = vTimer500msTake();
				}

				/* Turn Display Alarm OFF via Timer. */
				if(_tmrDisplayAlarmOFF[1] == NULL) {
					/* Obtain Timer. */
					_tmrDisplayAlarmOFF[1] = vTimer500msTake();
				}

				if(_tmrDisplayAlarmOFF[0] != NULL) {
					if(_DisplayAlarmOFF_Active_Flag[0] < 2) {
						*_tmrDisplayAlarmOFF[0] = _val;
					}

					if(_DisplayAlarmOFF_Active_Flag[0] == 0) {
						_DisplayAlarmOFF_Active_Flag[0] = 1;
						_funcTurnDisplayAlarmOff[0] = &prvTurnOffDisplayAlarm1;
						vTimer500msFuncReg(_funcTurnDisplayAlarmOff[0], (void *)_tmrDisplayAlarmOFF[0]);
					}
				}

				if(_tmrDisplayAlarmOFF[1] != NULL) {
					if(_DisplayAlarmOFF_Active_Flag[1] < 2) {
						*_tmrDisplayAlarmOFF[1] = _val;
					}

					if(_DisplayAlarmOFF_Active_Flag[1] == 0) {
						_DisplayAlarmOFF_Active_Flag[1] = 1;
						_funcTurnDisplayAlarmOff[1] = &prvTurnOffDisplayAlarm2;
						vTimer500msFuncReg(_funcTurnDisplayAlarmOff[1], (void *)_tmrDisplayAlarmOFF[1]);
					}
				}
			}
			/* One selected Display Alarm OFF. */
			else {
				/* Turn Display Alarm OFF via Timer. */
				if(_tmrDisplayAlarmOFF[_idx] == NULL) {
					/* Obtain Timer. */
					_tmrDisplayAlarmOFF[_idx] = vTimer500msTake();
				}

				if(_tmrDisplayAlarmOFF[_idx] != NULL) {
					if(_DisplayAlarmOFF_Active_Flag[_idx] < 2) {
						*_tmrDisplayAlarmOFF[_idx] = _val;
					}

					if(_idx == 0) {
						if(_DisplayAlarmOFF_Active_Flag[0] == 0) {
							_DisplayAlarmOFF_Active_Flag[0] = 1;
							_funcTurnDisplayAlarmOff[0] = &prvTurnOffDisplayAlarm1;
							vTimer500msFuncReg(_funcTurnDisplayAlarmOff[0], (void *)_tmrDisplayAlarmOFF[0]);
						}
					}
					else if(_idx == 1) {
						if(_DisplayAlarmOFF_Active_Flag[1] == 0) {
							_DisplayAlarmOFF_Active_Flag[1] = 1;
							_funcTurnDisplayAlarmOff[1] = &prvTurnOffDisplayAlarm2;
							vTimer500msFuncReg(_funcTurnDisplayAlarmOff[1], (void *)_tmrDisplayAlarmOFF[1]);
						}
					}
				}
			}
		break;

		default: break;
	}

	return 0;
}




static void prvTurnOnDisplayAlarm1(void *_tmr)
{
	uint32_t *_ptr = _tmr;

	if(*_ptr == 0) {
		_DisplayAlarmON_Active_Flag[0] = 2;
		/* Turn Display Alarm On. */
		gpio_set_pin_high(PINC0_GPIO);
		/* Unregister the function from list. */
		vTimer500msFuncUnreg(_funcTurnDisplayAlarmOn[0]);
		/* Release Timers. */
		vTimer500msGive(_tmr);
	}
}

static void prvTurnOnDisplayAlarm2(void *_tmr)
{
	uint32_t *_ptr = _tmr;

	if(*_ptr == 0) {
		_DisplayAlarmON_Active_Flag[1] = 2;
		/* Turn Display Alarm On. */
		gpio_set_pin_high(PINC1_GPIO);
		/* Unregister the function from list. */
		vTimer500msFuncUnreg(_funcTurnDisplayAlarmOn[1]);
		/* Release Timers. */
		vTimer500msGive(_tmr);
	}
}


static void prvTurnOffDisplayAlarm1(void *_tmr)
{
	uint32_t *_ptr = _tmr;

	if(*_ptr == 0) {
		_DisplayAlarmOFF_Active_Flag[0] = 0;
		_DisplayAlarmON_Active_Flag[0] = 0;
		/* Turn Display Alarm On. */
		gpio_set_pin_low(PINC0_GPIO);
		/* Unregister the function from list. */
		vTimer500msFuncUnreg(_funcTurnDisplayAlarmOff[0]);
		/* Release Timers. */
		vTimer500msGive(_tmr);
	}
}


static void prvTurnOffDisplayAlarm2(void *_tmr)
{
	uint32_t *_ptr = _tmr;

	if(*_ptr == 0) {
		_DisplayAlarmOFF_Active_Flag[1] = 0;
		_DisplayAlarmON_Active_Flag[1] = 0;
		/* Turn Display Alarm On. */
		gpio_set_pin_low(PINC1_GPIO);
		/* Unregister the function from list. */
		vTimer500msFuncUnreg(_funcTurnDisplayAlarmOff[1]);
		/* Release Timers. */
		vTimer500msGive(_tmr);
	}
}



#endif /* APPLICATION_CNG */
